#include "serveroperation.h"

ServerOperation::ServerOperation() {
}

void ServerOperation::exec(InfoHead *infoHead, QByteArray data, QHostAddress ip, quint16 port) {
    qDebug() << "Server exec" << "op=" << QString::number(infoHead->getOperation());
    QJsonDocument doc = QJsonDocument::fromJson(data);
    qDebug() << "data:" << data;
    qDebug() << doc.object().size();
    for (auto each: doc.object().keys()) {
        qDebug() << "each = " << each;
    }
    if (!DB.open()) {
        qDebug() << "\033[31mFailed to open database \033[0m";
        return;
    }
    switch (static_cast<Opcode>(infoHead->getOperation())) {
        case ServerOperation::RePingOnline:
            rePingOnline(infoHead, doc, ip, port);
            break;
        case ServerOperation::SignIn:
            signIn(infoHead, doc, ip, port);
            break;
        case ServerOperation::SignUpInfo:
            signUpInfo(infoHead, doc, ip, port);
            break;
        case ServerOperation::ModifyPassword:
            modifyPassword(infoHead, doc, ip, port);
            break;
        case ServerOperation::SendTextMsg:
            sendTextMsg(infoHead, doc, ip, port);
            break;
        case ServerOperation::GetNewFriend:
            getNewFriend(infoHead, doc, ip, port);
            break;
        case ServerOperation::AddNewFriend:
            addNewFriend(infoHead, doc, ip, port);
            break;
        case ServerOperation::AgreeNewFriend:
            agreeNewFriend(infoHead, doc, ip, port);
            break;
        case ServerOperation::SendGroupTextMsg:
            sendGroupTextMsg(infoHead, doc, ip, port);
            break;
        default:
            defaultReturn();
    }
}

// 50001
void ServerOperation::rePingOnline(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port) {

}

// 3000
void ServerOperation::getNewFriend(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();
    QString account = obj["account"].toString();
    QSqlTableModel *userInfoModel = new QSqlTableModel();
    userInfoModel->setTable("user_info");

    userInfoModel->setFilter(QObject::tr("account = '%1'").arg(account));
    userInfoModel->select();

    QJsonDocument redoc;
    QJsonObject reobj;
    obj.insert("id", userInfoModel->record(0).value("id").toString());
    obj.insert("name", userInfoModel->record(0).value("name").toString());
    obj.insert("email", userInfoModel->record(0).value("email").toString());
    obj.insert("age", userInfoModel->record(0).value("age").toString());
    obj.insert("phone_number", userInfoModel->record(0).value("phone_number").toString());
    obj.insert("level", userInfoModel->record(0).value("level").toString());
    obj.insert("avator", userInfoModel->record(0).value("avator").toString());
    redoc.setObject(reobj);

    DB.close();

    QByteArray bytes = doc.toJson();
    int fileSize = bytes.size();

    InfoHead *reInfoHead = new InfoHead(fileSize, 0, ReGetNewFriend, Operation::Success,
                                        infoHead->getSrc(), 0, QString(""));
    TRANS->writeUdp(reInfoHead, bytes, ip, port);

}

//3001
void ServerOperation::addNewFriend(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();

    QSqlTableModel *contactModel = new QSqlTableModel();
    contactModel->setTable("contact");

    QSqlRecord record1 = contactModel->record();
    QSqlRecord record2 = contactModel->record();
    record1.setValue("user1", obj["id"].toInt());
    record1.setValue("user2", infoHead->getSrc());
    record2.setValue("user1", infoHead->getSrc());
    record2.setValue("user2", obj["id"].toInt());

    contactModel->setFilter(nullptr);
    contactModel->select();
    contactModel->insertRecord(contactModel->rowCount(), record1);
    contactModel->insertRecord(contactModel->rowCount(), record2);
    DB.close();

    InfoHead *reInfoHead = new InfoHead(0, 0, ReAddNewFriend, Success, 0, 0, QString(""));
    TRANS->writeUdp(reInfoHead, QByteArray(), ip, port);

}


void ServerOperation::agreeNewFriend(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();
    QString check_result = obj["check_result"].toString();

    if (check_result == "Yes"){
        qint32 id1 = infoHead->getSrc();
        qint32 id2 = obj["id"].toInt();

        QSqlTableModel *contactModel = new QSqlTableModel();
        contactModel->setTable("contact");

        QSqlRecord record1 = contactModel->record();
        QSqlRecord record2 = contactModel->record();
        record1.setValue("user1", id1);
        record1.setValue("user2", id2);
        record2.setValue("user1", id2);
        record2.setValue("user2", id1);

        contactModel->setFilter(nullptr);
        contactModel->select();
        contactModel->insertRecord(contactModel->rowCount(), record1);
        contactModel->insertRecord(contactModel->rowCount(), record2);
        DB.close();

        InfoHead *reInfoHead = new InfoHead(0, 0, ReAgreeNewFriend, Success, 0, 0, QString(""));
        TRANS->writeUdp(reInfoHead, QByteArray(), ip, port);
    }else{

    }

}

//3002
void ServerOperation::getFriendList(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    qint32 id = infoHead->getSrc();

    QSqlTableModel *contactModel = new QSqlTableModel();
    QSqlTableModel *userInfoModel = new QSqlTableModel();
    contactModel->setTable("contact");
    userInfoModel->setTable("user_info");

    QJsonDocument reDoc;
    QJsonObject rootObj;
    QJsonArray arr;

    contactModel->setFilter(QObject::tr("user1 = '%1'").arg(id));
    contactModel->select();
    int recordSize = contactModel->rowCount();
    for (int i = 0; i < recordSize; i ++) {
        QSqlRecord contactRecord = contactModel->record(i);

        int friendId = contactRecord.value("user2").toInt();
        userInfoModel->setFilter(QObject::tr("id = '%1'").arg(friendId));
        userInfoModel->select();
        QString name = userInfoModel->record(0).value("name").toString();

        QJsonObject obj;
        obj.insert("name", name);
        arr.append(obj);
    }

    rootObj.insert("friendList", arr);
    doc.setObject(rootObj);

    DB.close();

    QByteArray bytes = doc.toJson();
    int fileSize = bytes.size();

    InfoHead *reInfoHead = new InfoHead(fileSize, 0, Operation::ReGetFriendList, Operation::Success,
                                        infoHead->getSrc(), 0, QString(""));
    TRANS->writeUdp(reInfoHead, bytes, ip, port);

}

//3003
void ServerOperation::getFriendInfo(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();
    qint32 friendId = obj["id"].toInt();

    QSqlTableModel *userInfoModel = new QSqlTableModel();
    userInfoModel->setTable("user_info");

    userInfoModel->setFilter(QObject::tr("id = '%1'").arg(friendId));
    userInfoModel->select();

    QJsonDocument redoc;
    QJsonObject reobj;
    obj.insert("id", userInfoModel->record(0).value("id").toString());
    obj.insert("name", userInfoModel->record(0).value("name").toString());
    obj.insert("email", userInfoModel->record(0).value("email").toString());
    obj.insert("age", userInfoModel->record(0).value("age").toString());
    obj.insert("phone_number", userInfoModel->record(0).value("phone_number").toString());
    obj.insert("level", userInfoModel->record(0).value("level").toString());
    obj.insert("avator", userInfoModel->record(0).value("avator").toString());
    redoc.setObject(reobj);

    DB.close();

    QByteArray bytes = doc.toJson();
    int fileSize = bytes.size();

    InfoHead *reInfoHead = new InfoHead(fileSize, 0, ReGetFriendInfo, Operation::Success,
                                        infoHead->getSrc(), 0, QString(""));
    TRANS->writeUdp(reInfoHead, bytes, ip, port);

}

//4000
void ServerOperation::getNewGroup(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();
    QString name = obj["name"].toString();
    QSqlTableModel *userInfoModel = new QSqlTableModel();
    userInfoModel->setTable("group_list");

    userInfoModel->setFilter(QObject::tr("name = '%1'").arg(name));
    userInfoModel->select();

    QJsonDocument redoc;
   QJsonObject reObj;
    obj.insert("id", userInfoModel->record(0).value("id").toString());
    obj.insert("name", userInfoModel->record(0).value("name").toString());
    obj.insert("count", userInfoModel->record(0).value("count").toString());
    obj.insert("scale", userInfoModel->record(0).value("scale").toString());
    obj.insert("avator", userInfoModel->record(0).value("avator").toString());
    redoc.setObject(reObj);

    DB.close();

    QByteArray bytes = doc.toJson();
    int fileSize = bytes.size();

    InfoHead *reInfoHead = new InfoHead(fileSize, 0, ReGetNewGroup, Operation::Success,
                                        infoHead->getSrc(), 0, QString(""));
    TRANS->writeUdp(reInfoHead, bytes, ip, port);
}

//4001
void ServerOperation::addNewGroup(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();

    QSqlTableModel *model = new QSqlTableModel();
    model->setTable("group_user");

    QSqlRecord record = model->record();
    record.setValue("user_id", infoHead->getSrc());
    record.setValue("group_id", infoHead->getDes());
    record.setValue("permission", "normal");

    model->setFilter(nullptr);
    model->select();
    model->insertRecord(model->rowCount(), record);
    DB.close();

    InfoHead *reInfoHead = new InfoHead(0, 0, ReAddNewGroup, Success, 0, 0, QString(""));
    TRANS->writeUdp(reInfoHead, QByteArray(), ip, port);
}

//4002
void ServerOperation::getGroupList(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    qint32 id = infoHead->getSrc();

    QSqlTableModel *groupModel = new QSqlTableModel();
    QSqlTableModel *userModel = new QSqlTableModel();
    groupModel->setTable("group_list");
    userModel->setTable("group_user");

    QJsonDocument reDoc;
    QJsonObject rootObj;
    QJsonArray arr;

    userModel->setFilter(QObject::tr("user_id = '%1'").arg(id));
    userModel->select();
    int recordSize = userModel->rowCount();
    for (int i = 0; i < recordSize; i ++) {
        QSqlRecord contactRecord = userModel->record(i);

        int groupId = contactRecord.value("group_id").toInt();
        groupModel->setFilter(QObject::tr("id = '%1'").arg(groupId));
        groupModel->select();
        if (groupModel->rowCount() != 1) continue;
        QString name = groupModel->record(0).value("name").toString();

        QJsonObject obj;
        obj.insert("name", name);
        arr.append(obj);
    }

    rootObj.insert("groupList", arr);
    doc.setObject(rootObj);

    DB.close();

    QByteArray bytes = doc.toJson();
    int fileSize = bytes.size();

    InfoHead *reInfoHead = new InfoHead(fileSize, 0, Operation::ReGetGroupList, Operation::Success,
                                        infoHead->getSrc(), 0, QString(""));
    TRANS->writeUdp(reInfoHead, bytes, ip, port);
}

//4003
void ServerOperation::getGroupInfo(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();
    qint32 groupId = obj["id"].toInt();

    QSqlTableModel *groupInfoModel = new QSqlTableModel();
    groupInfoModel->setTable("group_list");

    groupInfoModel->setFilter(QObject::tr("id = '%1'").arg(groupId));
    groupInfoModel->select();

    QJsonDocument redoc;
    QJsonObject reobj;
    obj.insert("id", groupInfoModel->record(0).value("id").toString());
    obj.insert("name", groupInfoModel->record(0).value("name").toString());
    obj.insert("count", groupInfoModel->record(0).value("count").toString());
    obj.insert("scale", groupInfoModel->record(0).value("scale").toString());
    obj.insert("avator", groupInfoModel->record(0).value("avator").toString());
    obj.insert("signature", groupInfoModel->record(0).value("signature").toString());
    redoc.setObject(reobj);

    DB.close();

    QByteArray bytes = doc.toJson();
    int fileSize = bytes.size();

    InfoHead *reInfoHead = new InfoHead(fileSize, 0, ReGetGroupInfo, Operation::Success,
                                        infoHead->getSrc(), 0, QString(""));
    TRANS->writeUdp(reInfoHead, bytes, ip, port);
}

//1000
// port user2
void ServerOperation::signIn(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port) {
    QJsonObject obj = doc.object();
    QString account = obj["account"].toString();
    QString password = obj["password"].toString();

    QSqlTableModel *userInfoModel = new QSqlTableModel();
    userInfoModel->setTable("user_info");
    QSqlTableModel *contactModel = new QSqlTableModel();
    contactModel->setTable("contact");
    QSqlTableModel *groupUserModel = new QSqlTableModel();
    groupUserModel->setTable("group_user");
    QSqlTableModel *groupModel = new QSqlTableModel();
    groupModel->setTable("group_list");

    userInfoModel->setFilter(QObject::tr("account = '%1'").arg(account));
    userInfoModel->select();

    if (userInfoModel->record(0).value("password").toString() == password) {
        QJsonDocument doc;
        QJsonObject rootObj;
        QJsonArray arr;
        QJsonArray groupArr;

        int id = userInfoModel->record(0).value("id").toInt();

        rootObj.insert("id", id);

        contactModel->setFilter(QObject::tr("user1 = %1").arg(id));
        contactModel->select();

        int recordSize = contactModel->rowCount();
        for (int i = 0; i < recordSize; i ++) {
            QSqlRecord contactRecord = contactModel->record(i);
            QString recentTime = contactRecord.value("recent_time").toString();
            QString recentMsg = contactRecord.value("recent_msg").toString();

            int reId = contactRecord.value("user2").toInt();
            userInfoModel->setFilter(QObject::tr("id = %1").arg(reId));
            userInfoModel->select();
            if (userInfoModel->rowCount() != 1) continue;
            QString name = userInfoModel->record(0).value("name").toString();
            QString avator = userInfoModel->record(0).value("avator").toString();

            QJsonObject obj;
            obj.insert("name", name);
            obj.insert("time", recentTime);
            obj.insert("msg", recentMsg);
            obj.insert("id", reId);
            obj.insert("avator", avator);

            arr.append(obj);
        }

        groupUserModel->setFilter(QObject::tr("user_id = %1").arg(id));
        groupUserModel->select();

        int groupRecordSize = groupUserModel->rowCount();
        for (int i = 0; i < groupRecordSize; i ++) {
            int groupId = groupUserModel->record(i).value("group_id").toInt();
            qDebug() << "groupId:" << groupId;
            groupModel->setFilter(QObject::tr("id = %1").arg(groupId));
            groupModel->select();
            qDebug() << "rowCount:" << groupModel->rowCount();
            QString groupName = groupModel->record(0).value("name").toString();
            int count = groupModel->record(0).value("count").toInt();
            QString groupSignature = groupModel->record(0).value("signature").toString();
            int scale = groupModel->record(0).value("scale").toInt();
            QString groupAvator = groupModel->record(0).value("avator").toString();
            QString recentMsg = groupUserModel->record(i).value("recent_msg").toString();
            QString recentTime = groupUserModel->record(i).value("recent_time").toString();

            QJsonObject groupObj;
            groupObj.insert("id", groupId);
            groupObj.insert("name", groupName);
            groupObj.insert("count", count);
            groupObj.insert("signature", groupSignature);
            groupObj.insert("scale", scale);
            groupObj.insert("avator", groupAvator);
            groupObj.insert("recentMsg", recentMsg);
            groupObj.insert("recentTime", recentTime);

            groupArr.append(groupObj);
        }

        rootObj.insert("recent", arr);
        rootObj.insert("recentGroup", groupArr);
        doc.setObject(rootObj);

        QByteArray bytes = doc.toJson();
        int fileSize = bytes.size();

        InfoHead *reInfoHead = new InfoHead(fileSize, 0, Operation::ReSignIn, Operation::Success,
                                            infoHead->getSrc(), 0, QString(""));
        TRANS->writeUdp(reInfoHead, bytes, ip, 7777);
//        qDebug() << "反馈"
    }
    else {
        InfoHead *reInfoHead = new InfoHead(0, 0, Operation::ReSignIn, Operation::Fail,
                                            infoHead->getSrc(), 0, QString(""));
        TRANS->writeUdp(reInfoHead, QByteArray(), ip, 7777);
    }
}

//1002
void ServerOperation::signUpInfo(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port) {
    QSqlTableModel *userInfoModel = new QSqlTableModel();
    userInfoModel->setTable("user_info");

    // TODO: 从QStringList改用QJsonDocument
    userInfoModel->setFilter(QObject::tr("account = '%1'")
                 .arg(doc.object()["account"].toString()));
    userInfoModel->select();

    QJsonDocument redoc;
    QJsonObject obj;

    if (userInfoModel->rowCount() == 0){
        QSqlRecord record = userInfoModel->record();
        record.setValue("account", doc.object()["account"].toString());
        record.setValue("password", doc.object()["password"].toString());
        record.setValue("name", doc.object()["name"].toString());
        record.setValue("email", doc.object()["email"].toString());
        record.setValue("age", doc.object()["age"].toInt());
        record.setValue("phone_number", doc.object()["phone_number"].toString());
        record.setValue("level", doc.object()["level"].toInt());
        record.setValue("avator", doc.object()["avator"].toString());
        userInfoModel->setFilter(nullptr);
        userInfoModel->select();
        userInfoModel->insertRecord(userInfoModel->rowCount(), record);
        DB.close();

        InfoHead *infoHead = new InfoHead(0, 0, ReSignUpInfo, Success, 0, 0, QString(""));
        TRANS->writeUdp(infoHead, QByteArray(), ip, port);


    }else{
        DB.close();
        InfoHead *infoHead = new InfoHead(0, 0, ReSignUpInfo, Fail, 0, 0, QString(""));
        TRANS->writeUdp(infoHead, QByteArray(), ip, port);
    }

}

//1003
void ServerOperation::modifyPassword(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port) {

}

//1004
void ServerOperation::alterPersonalInfo(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port){
    QJsonObject obj = doc.object();

    QSqlTableModel *userInfoModel = new QSqlTableModel();
    userInfoModel->setTable("user_info");

    userInfoModel->setFilter(QObject::tr("id == %1").arg(doc.object()["id"].toString()));
    userInfoModel->select();
    if (userInfoModel->rowCount() == 1){

    }

    QSqlRecord record = userInfoModel->record();
    record.setValue("account", doc.object()["account"].toString());
    record.setValue("password", doc.object()["password"].toString());
    record.setValue("name", doc.object()["name"].toString());
    record.setValue("email", doc.object()["email"].toString());
    record.setValue("age", doc.object()["age"].toInt());
    record.setValue("phone_number", doc.object()["phone_number"].toString());
    record.setValue("level", doc.object()["level"].toInt());
    record.setValue("avator", doc.object()["avator"].toString());

    InfoHead *reInfoHead = new InfoHead(0, 0, ReAlterPersonalInfo, Success, 0, 0, QString(""));
    TRANS->writeUdp(infoHead, QByteArray(), ip, port);

}

//2000
void ServerOperation::sendTextMsg(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port) {
    QJsonObject obj;
    obj.insert("msg", doc.object()["msg"].toString());
    QJsonDocument redoc;
    redoc.setObject(obj);

    QSqlTableModel *model = new QSqlTableModel();
    model->setTable("user_ip");
    model->setFilter(QObject::tr("user_id = %1")
                     .arg(infoHead->getDes()));
    model->select();

    qDebug() << "client ip:" << model->record(0).value("ip").toString();
    qDebug() << "发来的消息：" << doc.object()["msg"].toString();
    qDebug() << "转发的消息：" << redoc.object()["msg"].toString();

    TRANS->writeUdp(new InfoHead(redoc.toJson().size(), 0, Operation::ReSendTextMsg,
                                 Operation::Success, infoHead->getSrc(), infoHead->getDes(),
                                 QString("")),
                    redoc.toJson(),
                    QHostAddress(model->record(0).value("ip").toString()),
                    port);
}

void ServerOperation::sendGroupTextMsg(InfoHead *infoHead, QJsonDocument doc, QHostAddress ip, quint16 port) {
    QJsonObject obj;
    QString msg = doc.object()["msg"].toString();
    int id;

    if (msg.left(6) == "@robot") {
        id = 0;
        msg = msg.mid(7);
        Robot *robot = new Robot();
        robot->setQuestion(msg);
        robot->run();
        loop = new QEventLoop();
        connect(robot, SIGNAL(reRobotMsg()), this, SLOT(exitLoop()));
        loop->exec();
        msg = robot->strQuestion();
        qDebug() << "msgggggggg" << msg;
        robot->deleteLater();
    }
    else {
        id = infoHead->getSrc();
    }

    qDebug() << "msg" << msg;

    obj.insert("msg", msg);
    QJsonDocument redoc;
    redoc.setObject(obj);
    QByteArray bytes = redoc.toJson();

    QSqlTableModel *groupModel = new QSqlTableModel();
    groupModel->setTable("group_user");
    groupModel->setFilter(QObject::tr("group_id = %1").arg(infoHead->getDes()));
    groupModel->select();

    QSqlTableModel *userIpModel = new QSqlTableModel();
    userIpModel->setTable("user_ip");

    int rowCount = groupModel->rowCount();

    for (int i = 0; i < rowCount; i ++) {
        int reId = groupModel->record(i).value("user_id").toInt();
        userIpModel->setFilter(QObject::tr("user_id = %1").arg(reId));
        userIpModel->select();
        if (userIpModel->rowCount() != 1 || reId == id) continue;
        QHostAddress reIp(userIpModel->record(0).value("ip").toString());
        InfoHead *reInfoHead = new InfoHead(bytes.size(), 0, Operation::ReSendGroupTextMsg, Operation::Success,
                                            id, infoHead->getDes(), QString(""));
        TRANS->writeUdp(reInfoHead, bytes, reIp, SYSCONF.udpPort);
        if (id == 0) break;
    }
}

void ServerOperation::defaultReturn() {
    qDebug() << "\033[32mServerOperation::exec switch in default case \033[0m";
}

void ServerOperation::exitLoop()
{
    qDebug() << "exit";
    this->loop->quit();
}
